#pragma once
#include <arpa/inet.h>
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <mutex>
#include <netinet/in.h>
#include <stdexcept>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>

namespace net {
#define IO_NONE 0
#define IO_READ 1
#define IO_WRITE 2
#define IO_READWRITE 3

class IOListener {
  private:
    // std::mutex epoll_mtx_;
    int epoll_{0};

  public:
    IOListener(/* args */) : epoll_(epoll_create(1)){};
    virtual ~IOListener()
    {
        if (epoll_ >= 0)
            close(epoll_);
    };

    void         BindIO(int fd, int events, void* userdata);
    virtual void WaitIO(int event){};
    void         UnbindIO(int fd);

    int GetEpoll() const
    {
        // printf("GetEpoll:%d.\n", epoll_);
        return epoll_;
    }

    virtual void OnReadable(){};
    virtual void OnWritable(){};
};

class Socket {
  public:
    int             id_{0};
    int             type_{0};
    int             ctx{0};
    uint32_t        ip;
    std::atomic_int send_count_{10};  //发送计数器,发送空闲状态是发送心跳包
    std::atomic_int recv_count_{10};  //接收计数器,长时间没接收到数据时，认为链接断开

    //数据存储
    std::vector<char> recvdata_;
    char*             rbuf          = NULL;
    int               recvlen_      = 0;
    int               wantlen_      = 0;  //期望获得的数据总长度
    uint32_t          tmplen_       = 0;  //临时数据长度调试用
    std::vector<char> tmpdata_;
    bool              b_ignore      = false;
    bool              b_proto_head_ = true;
    bool              b_get_head_ = false;

    struct timeval curs_t_;
    std::mutex     curs_t_mtx_;

  public:
    Socket(/* args */);
    virtual ~Socket();

    void SetId(int id)
    {
        id_ = id;
    }
    bool    Connect(const std::string& ip, int port);
    bool    Listen(const std::string& ip, int port);
    Socket* Accept();
    int     Recv(char* buf, size_t size);
    bool    Send(const char* data, size_t size);
    bool    GetHeartBeatStatus();
    void    Close();

  private:
    std::mutex snd_mutex_;
};

}  // namespace net